//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<DwmComposite.cpp>
///	@path	~/src/editor/wm/
///	@date	2008/10/27
///	@desc	.

#include "config/config.h"

#include "editor/wm/DwmComposite.h"

#if WINVER >= 0x0600
#include <dwmapi.h>
#endif

//////////////////////////////////////////////////////////////////////////
// From <dwmapi.h>

#ifndef _DWMAPI_H_

typedef struct _DWM_BLURBEHIND
{
    DWORD dwFlags;
    BOOL fEnable;
    HRGN hRgnBlur;
    BOOL fTransitionOnMaximized;
} DWM_BLURBEHIND, *PDWM_BLURBEHIND;

#define DWM_BB_ENABLE                 0x00000001  // fEnable has been specified
#define DWM_BB_BLURREGION             0x00000002  // hRgnBlur has been specified
#define DWM_BB_TRANSITIONONMAXIMIZED  0x00000004  // fTransitionOnMaximized has been specified

#endif /*_DWMAPI_H_*/

//////////////////////////////////////////////////////////////////////////
// From <uxtheme.h>

#ifndef _UXTHEME_H_

typedef struct _MARGINS
{
    int cxLeftWidth;      // width of left border that retains its size
    int cxRightWidth;     // width of right border that retains its size
    int cyTopHeight;      // height of top border that retains its size
    int cyBottomHeight;   // height of bottom border that retains its size
} MARGINS, *PMARGINS;

// BP_BUFFERFORMAT
typedef enum _BP_BUFFERFORMAT
{
    BPBF_COMPATIBLEBITMAP,    // Compatible bitmap
    BPBF_DIB,                 // Device-independent bitmap
    BPBF_TOPDOWNDIB,          // Top-down device-independent bitmap
    BPBF_TOPDOWNMONODIB       // Top-down monochrome device-independent bitmap
} BP_BUFFERFORMAT;

// BP_PAINTPARAMS
typedef struct _BP_PAINTPARAMS
{
    DWORD                       cbSize;
    DWORD                       dwFlags; // BPPF_ flags
    const RECT *                prcExclude;
    const BLENDFUNCTION *       pBlendFunction;
} BP_PAINTPARAMS, *PBP_PAINTPARAMS;

typedef void * HPAINTBUFFER;

#define BPPF_ERASE			0x001

#endif /*_UXTHEME_H_*/

//////////////////////////////////////////////////////////////////////////

typedef HRESULT (STDAPICALLTYPE *pDwmIsCompositionEnabledFn)(BOOL*);
typedef HRESULT (STDAPICALLTYPE *pDwmEnableCompositionFn)(UINT);
typedef HRESULT (STDAPICALLTYPE *pDwmEnableBlurBehindWindowFn)(HWND,const DWM_BLURBEHIND*);
typedef HRESULT (STDAPICALLTYPE *pDwmExtendFrameIntoClientAreaFn)(HWND,const MARGINS*);

typedef HPAINTBUFFER (STDAPICALLTYPE *pBeginBufferedPaintFn)(HDC,const RECT*,BP_BUFFERFORMAT,BP_PAINTPARAMS *,HDC*);
typedef HRESULT (STDAPICALLTYPE *pEndBufferedPaintFn)(HPAINTBUFFER,BOOL);

namespace xeres {

	namespace
	{
		// Vista tag.
		static const bool is_vista = IsVista();

		/*! 
			\class	DwmApi
			\brief	Manages dwm api.
		*/
		class DwmApi
		{
		public:

			/// \instance
			static DwmApi& instance( void )
			{
				static DwmApi s_dwmapiInstance;
				return s_dwmapiInstance;
			}

			HRESULT DwmEnableComposition( UINT uCompositionAction )
			{
				if( !m_moduleDwm || !m_DwmEnableComposition )
					return -1;
				return m_DwmEnableComposition( uCompositionAction );
			}

			HRESULT DwmEnableBlurBehindWindow( HWND hWnd, const DWM_BLURBEHIND* pBlurBehind )
			{
				if( !m_moduleDwm || !m_DwmEnableBlurBehindWindow )
					return -1;
				return m_DwmEnableBlurBehindWindow( hWnd , pBlurBehind );
			}
			
			HRESULT DwmExtendFrameIntoClientArea( HWND hWnd, const MARGINS* pMarInset )
			{
				if( !m_moduleDwm || !m_DwmExtendFrameIntoClientArea )
					return -1;
				return m_DwmExtendFrameIntoClientArea( hWnd , pMarInset );
			}

			HRESULT DwmIsCompositionEnabled( BOOL* pfEnabled )
			{
				if( !m_moduleDwm || !m_DwmIsCompositionEnabled )
				{
					*pfEnabled = FALSE;
					return S_OK;
				}
				return m_DwmIsCompositionEnabled( pfEnabled );
			}

			HPAINTBUFFER BeginBufferedPaint( HDC hdcTarget, const RECT* prcTarget, BP_BUFFERFORMAT dwFormat, BP_PAINTPARAMS *pPaintParams,
				HDC *phdc )
			{
				if( !m_moduleTheme || !m_BeginBufferedPaint )
					return NULL;
				return m_BeginBufferedPaint( hdcTarget, prcTarget, dwFormat, pPaintParams, phdc );
			}
			
			HRESULT EndBufferedPaint( HPAINTBUFFER hBufferedPaint, BOOL fUpdateTarget )
			{
				if( !m_moduleTheme || !m_EndBufferedPaint )
					return NULL;
				return m_EndBufferedPaint( hBufferedPaint , fUpdateTarget );
			}

		private:

			/// \ctor
			DwmApi( void )
				: m_moduleDwm( NULL )
				, m_moduleTheme( NULL )
				, m_DwmIsCompositionEnabled( NULL )
				, m_DwmEnableComposition( NULL )
				, m_DwmEnableBlurBehindWindow( NULL )
				, m_DwmExtendFrameIntoClientArea( NULL )
				, m_BeginBufferedPaint( NULL )
				, m_EndBufferedPaint( NULL )
			{

				// Load api entry.
#define LOAD_PROC( MODULE , NAME )	m_##NAME## = (p##NAME##Fn) ::GetProcAddress( MODULE , #NAME );

				// Try to load dwmapi.dll.
				if( !is_vista )
					return;

				m_moduleDwm = ::LoadLibrary( _S("dwmapi.dll") );
				if( m_moduleDwm == NULL )
					return;

				LOAD_PROC( m_moduleDwm , DwmIsCompositionEnabled );
				LOAD_PROC( m_moduleDwm , DwmEnableComposition );
				LOAD_PROC( m_moduleDwm , DwmEnableBlurBehindWindow );
				LOAD_PROC( m_moduleDwm , DwmExtendFrameIntoClientArea );

				m_moduleTheme = ::LoadLibrary( _S("uxtheme.dll") );
				if( m_moduleTheme == NULL )
					return;

				LOAD_PROC( m_moduleTheme , BeginBufferedPaint );
				LOAD_PROC( m_moduleTheme , EndBufferedPaint );
			}

			//@ data
			HMODULE			m_moduleDwm;
			HMODULE			m_moduleTheme;

			// function pointers.
			pDwmIsCompositionEnabledFn m_DwmIsCompositionEnabled;
			pDwmEnableCompositionFn m_DwmEnableComposition;
			pDwmEnableBlurBehindWindowFn	m_DwmEnableBlurBehindWindow;
			pDwmExtendFrameIntoClientAreaFn m_DwmExtendFrameIntoClientArea;

			pBeginBufferedPaintFn m_BeginBufferedPaint;
			pEndBufferedPaintFn m_EndBufferedPaint;
		};
	}
	
	// __dwm_is_composition_enable
	bool __dwm_is_composition_enable( void )
	{
 		if( !is_vista ) return false;

		BOOL enable = FALSE;
		DwmApi::instance().DwmIsCompositionEnabled( &enable );
		return enable != FALSE;
	}

	// __dwm_enable_composition
	bool __dwm_enable_composition( HWND hWnd )
	{
		if( !is_vista ) return false;

		DWM_BLURBEHIND bb = {0};
		bb.dwFlags = DWM_BB_ENABLE;
		bb.fEnable = true;
		bb.hRgnBlur = NULL;
		HRESULT hr = DwmApi::instance().DwmEnableBlurBehindWindow( hWnd , &bb );
		return SUCCEEDED(hr);
	}
	// __dwm_extend_composition
	bool __dwm_extend_composition( HWND hWnd )
	{
		if( !is_vista ) return false;

		MARGINS margins = {-1};
		HRESULT hr = DwmApi::instance().DwmExtendFrameIntoClientArea( hWnd , &margins );
		return SUCCEEDED(hr);
	}
	// __dwm_begin_paint
	HDC __dwm_begin_paint( HDC dc , RECT& rc , void ** context )
	{
		HDC pdc = NULL;
		BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
		BP_PAINTPARAMS params = {0};
		params.cbSize = sizeof(BP_PAINTPARAMS);
		params.dwFlags = BPPF_ERASE;
		params.prcExclude = NULL;
		params.pBlendFunction = NULL;
		HPAINTBUFFER buffer = DwmApi::instance().BeginBufferedPaint( dc , &rc , BPBF_COMPATIBLEBITMAP , &params , &pdc );
		*context = (void*)buffer;
		if( buffer )
			return pdc;
		else
			return dc;
	}
	// __dwm_end_paint
	void __dwm_end_paint( void ** context )
	{
		HPAINTBUFFER buffer = (HPAINTBUFFER)*context;
		if( buffer )
			DwmApi::instance().EndBufferedPaint( buffer , TRUE );
		*context = NULL;
	}
} // namespace xeres
